package com.wen.controller.system;


import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.wen.business.mapper.LoginLogMapper;
import com.wen.common.dto.LoginDTO;
import com.wen.common.pojo.account.LoginLog;
import com.wen.common.pojo.system.Permission;
import com.wen.common.pojo.system.Role;
import com.wen.common.pojo.system.User;
import com.wen.common.utils.DownloadImgUtil;
import com.wen.common.utils.JwtUtil;
import com.wen.common.utils.ResponseResult;
import com.wen.common.vo.CaptchaVO;
import com.wen.system.service.PermissionService;
import com.wen.system.service.UserService;
import com.wen.system.service.impl.CaptchaService;
import com.wen.system.wechatjson.Item;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import sun.misc.BASE64Encoder;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.*;
import java.sql.ResultSet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

/**
 * 这个类是为了让 vue登录的测试使用
 */
@Controller
@RequestMapping("/system")
public class LoginControllerVue {
    private static final Logger log = LoggerFactory.getLogger(LoginControllerVue.class);
    @Autowired
    HttpServletResponse responseAuto;
    @Autowired
    HttpSession session;

    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    private UserService userService;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private LoginLogMapper loginLogMapper;
    @Autowired
    private DefaultKaptcha producer;
    @Autowired
    private CaptchaService captchaService;
    @Autowired
    private DownloadImgUtil downloadImgUtil;
    @Autowired
    private EhCacheManager ehCacheManager;

    @CallerSensitive
    public static void main(String[] args) {
        LoginControllerVue loginController_vue = new LoginControllerVue();
        loginController_vue.callerSensitiveTest();
    }

    @ResponseBody
    @GetMapping("/getSql")
    public ResponseResult<?> testGetSql() {
        User user = userService.getUserById(1L);
        String sql = "SELECT  * FROM message WHERE parent_id IN (SELECT DISTINCT parent_id FROM message)";
        List<Map<String, Object>> list = jdbcTemplate.query(sql, new ColumnMapRowMapper());
        return ResponseResult.success(list);
    }
    @ResponseBody
    @GetMapping("/testBool")
    public ResponseResult<?> test() {
        TestBoolRet rtn = new TestBoolRet();
        rtn.isSuccess = true;
        rtn.isOnFlag = true;
        return ResponseResult.success(rtn);
    }

    /**
     * 生成base64格式的图片验证码
     * @return 验证码类
     * @throws IOException
     */
    @ResponseBody
    @GetMapping("/getCaptcha")
    public CaptchaVO getCaptcha() throws IOException {

        // 生成文字验证码
        String content = producer.createText();
        BufferedImage image = producer.createImage(content);
        // 生成图片验证码
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(image, "jpg", outputStream);
        // 对字节数组Base64编码
        BASE64Encoder encoder = new BASE64Encoder();

        String str = "data:image/jpeg;base64,";
        String base64Img = str + encoder.encode(outputStream.toByteArray()).replace("\n", "").replace("\r", "");

        CaptchaVO captchaVO = captchaService.cacheCaptcha(content);
        captchaVO.setBase64Img(base64Img);

        return captchaVO;
    }

    /**
     * 获取登录二维码
     *
     * @param request
     * @param response
     */
    //获取登录二维码、放入Token
    @GetMapping(value = "/getLoginQr")
    @ResponseBody
    public void createCodeImg(HttpServletRequest request, HttpServletResponse response) {
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");

        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");

        try {
            //这里没啥操作 就是生成一个UUID插入 数据库的表里
            String uuid = userService.createQrImg();
            response.setHeader("uuid", uuid);
            // 这里是开源工具类 hutool里的QrCodeUtil，需要额外引入com.google.zxing:core包
            // 网址：http://hutool.mydoc.io/
            QrCodeUtil.generate(uuid, 300, 300, "jpg", response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成图片验证码
     *
     * @throws IOException
     */
    @GetMapping("/getCode")
    @ResponseBody
    public void getCode() throws IOException { //HttpServletResponse response, HttpSession session

        // 利用 hutool 工具，生成验证码图片资源
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 5);
        // 获得生成的验证码字符
        String code = captcha.getCode();
        log.info("captcha code: : {}", code);
        // 利用 session 来存储验证码
        session.setAttribute("code", code);
        // 将验证码图片的二进制数据写入【响应体 response 】
        captcha.write(responseAuto.getOutputStream());

    }

    @CallerSensitive
    public void callerSensitiveTest() {
        Reflection.getCallerClass();
        try {
            Class<?> aClass = Class.forName("com.wen.SpringbootApplication");
            System.out.println(aClass.getSimpleName());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    // 表单登录
    /*@PostMapping("/doLogin")
    public String doLogin(LoginDto loginDto, HttpServletResponse response) {
        User user = userService.findUserByName(loginDto.getUsername());
        if (user == null) {
            throw new MyException("1001", "用户名不存在");
        }

        if (!user.getPassword().equals(loginDto.getPassword())*//*SecureUtil.md5(loginDto.getPassword()))*//*) {
            throw new MyException("1001", "密码错误");
        }
        //密码正确，创建jwt
        String jwt = jwtUtils.generateToken(user.getId());
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();

        //登录
        subject.login(new JwtToken(jwt));
        subject.getSession().setAttribute("user", loginDto.getUsername());

        response.setHeader("Authorization", jwt);
        response.setHeader("Access-Control-Expose-Headers", "Authorization");
        System.out.println(jwt);
        System.out.println(loginDto);
        return "index";
    }*/

    //    json的方式登录
    @PostMapping("/login")
    @ResponseBody
    public ResponseResult<?> doLogin(/*@Validated*/ @RequestBody LoginDTO loginDto, HttpServletResponse response) {
        User user = userService.login(loginDto);


        //登录成功记录登录日志 --aop
        LoginLog loginLog = new LoginLog();
        loginLog.setLoginUser(loginDto.getUsername());
        loginLog.setLoginIp("127.0.0.1");
        loginLog.setLoginAddress("上海市浦东新区xxxxx");
        loginLog.setLoginClient("chrome");
        loginLog.setLoginSystem("windows");
        loginLog.setInsertTime(System.currentTimeMillis());
        loginLog.setLoginTime(System.currentTimeMillis());

        loginLogMapper.insert(loginLog);

//        response.setHeader("token", String.valueOf(token));
//        response.setHeader("Access-control-Expose-Headers", "token");


        List<Role> roles = userService.getRoleByUserId(user.getId());

        List<Permission> menus = userService.getPermissionByUserId(user.getId());
        // 构造出菜单树
        List<Permission> menuTree = permissionService.getMenuTree(menus, 0);
//        return Result.success(user.getToken());

        Date iat = jwtUtil.getIssuedAt(user.getToken());
        Date exp = jwtUtil.getExpirationDate(user.getToken());
        System.out.println("iat: " + iat + "  exp: " + exp);
        return ResponseResult.success(MapUtil.builder()
                        .put("id", user.getId())
                        .put("username", user.getUserName())
//                .put("permissions", menuTree)
                        .put("roles", roles)
                        .put("nickName", user.getNickName())
                        .put("token", user.getToken())
                        .put("iat", iat)
                        .put("exp", exp)
                        .map()
        );
    }

    /**
     * 退出
     *
     * @return
     */
    @GetMapping("/loginOut")
    public String doLoginOut() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "index";
    }

    @GetMapping("content")
    @ResponseBody
    public String getContent() throws IOException {
        OkHttpClient httpClient = new OkHttpClient();
        String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wxc6778a4551bbf2d8&secret=47ba7229718e1912741a18aabcb39402";
        Request req = new Request.Builder().url(url).build();
        Response rep = httpClient.newCall(req).execute();
        String msg = rep.body().string();

        JSONObject jsonObject1 = JSONObject.parseObject(msg);
        String token = jsonObject1.get("access_token").toString();

        System.out.println("json" + jsonObject1);

        System.out.println(jsonObject1.get("access_token"));

        MediaType JSON
                = MediaType.parse("application/json; charset=utf-8");
        String body = "{\n" +
                "    \"type\":\"news\",\n" +
                "    \"offset\":0,\n" +
                "    \"count\":1\n" +
                "}";

        JSONObject jsonObject2 = JSONObject.parseObject(body);
        String url2 = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=" + token;
        okhttp3.RequestBody requestBody = okhttp3.RequestBody.create(JSON, jsonObject2.toJSONString());
        Request request = new Request.Builder()
                .url(url2)
                .post(requestBody)
                .build();

        Response httpClient2 = httpClient.newCall(request).execute();
        System.out.println("============最后结果=================");
        String articleItem = httpClient2.body().string();
        JSONObject jsonObject = JSONObject.parseObject(articleItem);
        JSONArray jsonArray = jsonObject.getJSONArray("item");
        Item item = jsonArray.getObject(0, Item.class);
        System.out.println(item);
        String html = item.getContent().getNews_item()[0].getContent().replace("data-", "");
        Document document = Jsoup.parse(html);
        Elements elements = document.getElementsByTag("img");
        int size = elements.size();
        for (Element e : elements) {
            String srcUrl = e.attr("src");
            String newSrcUrl = downloadImgUtil.downloadImg2Local(srcUrl);
            e.attr("src", newSrcUrl);
//            System.out.println(e);
        }
        String s = document.toString();


        return s;
    }

    //    @GetMapping("/put")
//    @ResponseBody
    public String put(String key, String value, int timeout) {
        CacheManager cacheManager = ehCacheManager.getCacheManager();
        String[] cacheNames = cacheManager.getCacheNames();
        System.out.println(Arrays.toString(cacheNames));
        Cache cache = cacheManager.getCache("shiro-activeSessionCache");
        net.sf.ehcache.Element element = new net.sf.ehcache.Element(key, value);
        element.setTimeToLive(timeout);
        cache.put(element);
        System.out.println("---------");
        System.out.println(cache.getKeys().size());
        return "ok";
    }

    @GetMapping("/put")
    @ResponseBody
    public String put1(String key, String value, int timeout) {
        CacheManager cacheManager = ehCacheManager.getCacheManager();
        String[] cacheNames = cacheManager.getCacheNames();
        System.out.println(Arrays.toString(cacheNames));
        Ehcache cache = cacheManager.getEhcache("logUser");
        net.sf.ehcache.Element element = new net.sf.ehcache.Element(key, value);
        element.setTimeToLive(timeout);
        cache.put(element);
        System.out.println("---------");
        System.out.println(cache.getKeys().size());
        return "ok";
    }

    @GetMapping("/keys")
    @ResponseBody
    public Object keys(String cacheName, boolean showValue) {
        CacheManager cacheManager = ehCacheManager.getCacheManager();
        Cache cache = cacheManager.getCache(cacheName);
        List keys = cache.getKeys();

        Map<Object, Object> res = new HashMap<>();
        keys.forEach(k -> {
            net.sf.ehcache.Element element = cache.get(k);
            System.out.println("element ==> " + element);
            res.put(k, element.getObjectValue());
        });


        return showValue ? res : keys;
    }

    @GetMapping("/getsession")
    @ResponseBody
    public Object gets(boolean showValue) {
        String cacheName = "logUser";
        CacheManager cacheManager = ehCacheManager.getCacheManager();
        Cache cache = cacheManager.getCache(cacheName);
        org.apache.shiro.cache.Cache<Object, Session> cache1 = ehCacheManager.getCache(cacheName);

        HashMap<Object, Object> sessionMap = new HashMap<>();
        Collection<Session> sessions = cache1.values();
        Set<Object> keys = cache1.keys();
        keys.forEach(key -> {
            Session session = cache1.get(key);

            Collection<Object> attributeKeys = session.getAttributeKeys();
            HashMap<Object, Object> map = new HashMap<>();
            for (Object attributeKey : attributeKeys) {
                Object attribute = session.getAttribute(attributeKey);
                map.put(attributeKey, attribute);
            }
            if (showValue) {
                sessionMap.put(key, map);

            } else {
//                sessionMap.put(key, session);
                sessionMap.put(key, "map.keySet()");
            }
        });

//        for (Object key : keys) {
//            Session session = cache1.get(key);
//
//            Collection<Object> attributeKeys = session.getAttributeKeys();
//            HashMap<Object, Object> map = new HashMap<>();
//            for (Object attributeKey : attributeKeys) {
//                Object attribute = session.getAttribute(attributeKey);
//                map.put(attributeKey, attribute);
//            }
//            if (showValue) {
//                sessionMap.put(session.getId(), map);
//
//            } else {
//                sessionMap.put(session.getId(), session);
//            }
//        }
        return sessionMap;
    }

    @GetMapping("/test/interceptor")
    @ResponseBody
    public List test(String name) {
        return Collections.emptyList();
    }

    @GetMapping("/caches")
    @ResponseBody
    public ResponseResult<?> test1(boolean showValue) {
        CacheManager cacheManager = ehCacheManager.getCacheManager();
        String[] cacheNames = cacheManager.getCacheNames();

        Map<Object, Object> cacheMap = new ConcurrentHashMap<>();
        Stream<String> cacheNameStream = Arrays.stream(cacheNames);
        int[] i = {0};
        System.out.println("cache count ==>" + cacheNameStream.count());
        ObjectMapper objectMapper = new ObjectMapper();
        Arrays.stream(cacheNames).forEach(name -> {
            Cache cache = cacheManager.getCache(name);
            // create a DTO object with the same properties as the cache object
            CacheDTO cacheDTO = new CacheDTO(name, cache);
            String s = null;
            try {
                s = objectMapper.writeValueAsString(cacheDTO);
            } catch (JsonProcessingException e) {
                log.info("serialize json error : {}", e.getLocalizedMessage());
            }
            System.out.println("caches forEach次数:" + ++i[0]);
            System.out.println("cache ==> " + cache);
            cacheMap.put(name, s);
//            cacheMap.put(name,i[0]++);

        });

//        return showValue ? cacheMap : Arrays.asList(cacheNames);
        System.out.println(cacheMap);
        return ResponseResult.success(cacheMap);
    }

    static class CacheDTO implements Serializable {
        private static final long serialVersionUID = 1L;

        private Object key;
        private Object value;

        public CacheDTO(Object key, Object value) {
            this.key = key;
            this.value = value;
        }

        public Object getKey() {
            return key;
        }

        public Object getValue() {
            return value;
        }
    }

    class TestBoolRet {
        public boolean isSuccess;
        public String name;
        private boolean isOnFlag;

        public boolean isSuccess() {
            return isSuccess;
        }
//
//        public boolean isOnFlag() {
//            return isOnFlag;
//        }
        /*
            页面显示的是name00。由此可见，spring将实体解析为json时，json的key是getXxx的xxx；Boolean类型的是is后面的名。--当有getter方法时（私有属性）
         */
//        public String getName00() {
//            return name;
//        }
    }


}
